#include "server/file_utils.h" // Will create this header next
#include "protocol.h"          // For file_entry_t
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>  // For R_OK etc. (though stat provides permissions)
#include <limits.h>  // For PATH_MAX
#include <sqlite3.h> // For sqlite3
#include <errno.h>   // Include for errno

// Base directory for all user uploads
// #define USER_UPLOADS_BASE_DIR "/tmp/sfts_uploads" // This is now passed as user_base_physical_dir

int list_uploaded_files_for_user(sqlite3 *db, int user_id, const char *user_base_physical_dir, const char *requested_virtual_path, file_entry_t **file_entries_list, int *count)
{
    // db is unused in this version but kept for future use (e.g., checking permissions from DB)
    if (!file_entries_list || !count || !requested_virtual_path || !user_base_physical_dir)
    {
        return -1; // Invalid arguments
    }

    *file_entries_list = NULL;
    *count = 0;

    char actual_path_to_scan[PATH_MAX];
    // Construct the full physical path to scan. requested_virtual_path is relative to user_base_physical_dir.
    // Basic concatenation: if requested_virtual_path is "/", it means the base itself.
    // If requested_virtual_path is "subfolder", it becomes "user_base_physical_dir/subfolder".
    if (strcmp(requested_virtual_path, "/") == 0 || strcmp(requested_virtual_path, "") == 0)
    {
        strncpy(actual_path_to_scan, user_base_physical_dir, sizeof(actual_path_to_scan) - 1);
    }
    else
    {
        // Ensure requested_virtual_path doesn't start with '/' if it's not the root, to prevent double slashes if base already has one.
        // This simple concatenation assumes user_base_physical_dir does NOT end with a slash,
        // and requested_virtual_path (if not "/") does NOT start with a slash.
        // More robust path joining is needed for production (e.g. handling .. , //, etc.)
        const char *path_to_append = requested_virtual_path;
        if (path_to_append[0] == '/')
        { // Avoid double slash if relative path accidentally starts with /
            path_to_append++;
        }
        snprintf(actual_path_to_scan, sizeof(actual_path_to_scan), "%s/%s", user_base_physical_dir, path_to_append);
    }
    actual_path_to_scan[sizeof(actual_path_to_scan) - 1] = '\0';

    // char user_actual_dir_path[PATH_MAX];
    // snprintf(user_actual_dir_path, sizeof(user_actual_dir_path), "%s/%d", USER_UPLOADS_BASE_DIR, user_id);

    // DIR *dir = opendir(user_actual_dir_path);
    DIR *dir = opendir(actual_path_to_scan);
    if (!dir)
    {
        // perror("opendir failed for user upload directory");
        // If directory does not exist (e.g. first time, or path is invalid), return empty file list with success.
        // This is not an error - just means the directory is empty or doesn't exist yet.
        fprintf(stderr, "[DEBUG file_utils] opendir failed for path: %s (errno: %d %s). Returning empty list.\n",
                actual_path_to_scan, errno, strerror(errno));

        // 为了确保客户端收到一个有效的空列表而不是错误，分配一个空数组
        *file_entries_list = malloc(0); // 分配一个空列表，确保返回的不是NULL
        *count = 0;
        return 0; // 返回成功，但列表为空
    }

    struct dirent *entry;
    int capacity = 10; // Initial capacity for file entries
    file_entry_t *temp_list = malloc(capacity * sizeof(file_entry_t));
    if (!temp_list)
    {
        closedir(dir);
        return -1; // Malloc failure
    }

    int current_file_count = 0;
    while ((entry = readdir(dir)) != NULL)
    {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }

        if (current_file_count >= capacity)
        {
            capacity *= 2;
            file_entry_t *new_temp_list = realloc(temp_list, capacity * sizeof(file_entry_t));
            if (!new_temp_list)
            {
                free(temp_list);
                closedir(dir);
                return -1; // Realloc failure
            }
            temp_list = new_temp_list;
        }

        file_entry_t *current_file_entry = &temp_list[current_file_count];
        strncpy(current_file_entry->name, entry->d_name, sizeof(current_file_entry->name) - 1);
        current_file_entry->name[sizeof(current_file_entry->name) - 1] = '\0';

        char full_item_path[PATH_MAX];
        // Check for potential overflow before calling snprintf
        size_t path_len = strlen(actual_path_to_scan);
        size_t name_len = strlen(entry->d_name);
        if (path_len + 1 + name_len + 1 > sizeof(full_item_path))
        { // +1 for '/', +1 for '\0'
            fprintf(stderr, "Error: Path and name too long for buffer: %s/%s\n", actual_path_to_scan, entry->d_name);
            // Decide how to handle: skip this entry, or report an error for the whole list?
            // For now, let's skip this entry.
            continue;
        }
        snprintf(full_item_path, sizeof(full_item_path), "%s/%s", actual_path_to_scan, entry->d_name);

        struct stat st;
        if (stat(full_item_path, &st) == 0)
        {
            current_file_entry->is_dir = S_ISDIR(st.st_mode) ? 1 : 0;
            // For now, we will only list files, not directories within the user's space.
            // If it is a directory, we could choose to skip it or list it differently.
            if (current_file_entry->is_dir)
            {
                // Skip directories for now in the file list, or handle as needed.
                // To list it, fill size as 0 or special value, and set appropriate permissions.
                // For this iteration, let's just skip it from the count of "files".
                continue;
            }
            current_file_entry->size = st.st_size;
            current_file_entry->modified_time = st.st_mtime;

            // Simplified permissions: if it's in their folder, they can read. Write could be default 0 or 1.
            current_file_entry->has_read_permission = 1;
            current_file_entry->has_write_permission = 0; // Or 1, depends on policy
        }
        else
        {
            // Failed to stat, maybe a broken symlink or permission issue on the item itself.
            // Set default/error values or skip. For now, let's fill with placeholder error.
            perror("stat failed for item in user directory");
            current_file_entry->is_dir = 0;
            current_file_entry->size = 0;
            current_file_entry->modified_time = 0;
            current_file_entry->has_read_permission = 0;
            current_file_entry->has_write_permission = 0;
        }
        current_file_count++;
    }
    closedir(dir);

    *file_entries_list = temp_list;
    *count = current_file_count;

    return 0; // Success
}